/*
 * Eduardo Nunes Pereira <eduardonunesp@gmail.com>
 */

// Defines, includes and global variables
// --------------------------------------

// User defines - standard
#define WINDOWMAKER true
#define USESHAPE    false
#define AFTERSTEP   false
#define NORMSIZE    64
#define ASTEPSIZE   56
#define NAME        "wmk"
#define CLASS       "WMK"

// User defines - custom
#define BACKCOLOR   "#282828"
#define LEDCOLOR    "green"

// Includes - standard
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

// X-Windows includes - standard
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xproto.h>
#include <X11/xpm.h>
#include <X11/extensions/shape.h>

// Pixmaps - standard
Pixmap pm_tile;
Pixmap pm_disp;
Pixmap pm_mask;

// Xpm images - standard
#include "XPM/wmmixer.xpm"
#include "XPM/tile.xpm"

// Xpm images - custom
#include "XPM/icons.xpm"
#include "XPM/norec.xpm"

// Variables for command-line arguments - standard
bool wmaker=WINDOWMAKER;
bool ushape=USESHAPE;
bool astep=AFTERSTEP;
char display[256]="";
char position[256]="";
int winsize;

// Variables for command-line arguments - custom
char backcolor[256]=BACKCOLOR;
char ledcolor[256]=LEDCOLOR;

// X-Windows basics - standard
Atom _XA_GNUSTEP_WM_FUNC;
Atom deleteWin;
Display *d_display;
Window w_icon;
Window w_main;
Window w_root;
Window w_activewin;

// X-Windows basics - custom
GC gc_gc;
unsigned long color[4];


// Misc custom global variables 
// ----------------------------

// Current state information
int curchannel=0;
bool curshowrec;
bool currec;
int curleft;
int curright;

// For buttons
int btnstate=0;
#define BTNNEXT  1
#define BTNPREV  2
#define BTNREC   4

// For repeating next and prev buttons
#define RPTINTERVAL   5
int rpttimer=0;

// Procedures and functions
// ------------------------

// Procedures and functions - standard
void initXWin(int argc, char **argv);
void freeXWin();
void createWin(Window *win, int x, int y);
unsigned long getColor(char *colorname);
unsigned long mixColor(char *colorname1, int prop1, char *colorname2, int prop2);

// Procedures and functions - custom
void scanArgs(int argc, char **argv);
void readFile();
void motionEvent(XMotionEvent *xev);
void repaint();
void update();

// Implementation
// --------------

int main(int argc, char **argv)
{
   scanArgs(argc, argv);
   initXWin(argc, argv);

   XGCValues gcv;
   unsigned long gcm;
   gcm=GCGraphicsExposures;
   gcv.graphics_exposures=false;
   gc_gc=XCreateGC(d_display, w_root, gcm, &gcv);

   color[0]=mixColor(ledcolor, 0, backcolor, 100);
   color[1]=mixColor(ledcolor, 100, backcolor, 0);
   color[2]=mixColor(ledcolor, 60, backcolor, 40);
   color[3]=mixColor(ledcolor, 25, backcolor, 75);

   XpmAttributes xpmattr;
   XpmColorSymbol xpmcsym[4]={{"back_color",     NULL, color[0]},
                              {"led_color_high", NULL, color[1]},
                              {"led_color_med",  NULL, color[2]},
                              {"led_color_low",  NULL, color[3]}};
   xpmattr.numsymbols=4;
   xpmattr.colorsymbols=xpmcsym;
   xpmattr.exactColors=false;
   xpmattr.closeness=40000;
   xpmattr.valuemask=XpmColorSymbols | XpmExactColors | XpmCloseness;
   XpmCreatePixmapFromData(d_display, w_root, tile_xpm, &pm_tile, NULL, &xpmattr);
   pm_disp=XCreatePixmap(d_display, w_root, 64, 64, DefaultDepth(d_display, DefaultScreen(d_display)));

   XCopyArea(d_display, pm_tile, pm_disp, gc_gc, 0, 0, 64, 64, 0, 0);
   XSetClipMask(d_display, gc_gc, pm_mask);
   XSetClipMask(d_display, gc_gc, None);

   XEvent xev;
   XSelectInput(d_display, w_activewin, ExposureMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask);
   XMapWindow(d_display, w_main);

   bool done=false;
   while(!done){
       while(XPending(d_display)){
           XNextEvent(d_display, &xev);
           switch(xev.type){
               case Expose:
                   repaint();
                   break;
               case ButtonPress:
                  // pressEvent(&xev.xbutton);
                   break;
               case ButtonRelease:
                  // releaseEvent(&xev.xbutton);
                   break;
               case MotionNotify:
                 //  motionEvent(&xev.xmotion);
                   break;
               case ClientMessage:
                   if(xev.xclient.data.l[0]==deleteWin)
                       done=true;
                   break;
           }
       }

       XFlush(d_display);
       usleep(50000);
   }

   XFreeGC(d_display, gc_gc);
   XFreePixmap(d_display, pm_tile);
   XFreePixmap(d_display, pm_disp);
   XFreePixmap(d_display, pm_mask);
   freeXWin();
   return 0;
}

void initXWin(int argc, char **argv){
   winsize=astep ? ASTEPSIZE : NORMSIZE;

   if((d_display=XOpenDisplay(display))==NULL){
      fprintf(stderr,"%s : Unable to open X display '%s'.\n", NAME, XDisplayName(display));
      exit(1);
   }
   _XA_GNUSTEP_WM_FUNC=XInternAtom(d_display, "_GNUSTEP_WM_FUNCTION", false);
   deleteWin=XInternAtom(d_display, "WM_DELETE_WINDOW", false);

   w_root=DefaultRootWindow(d_display);

   XWMHints wmhints;
   XSizeHints shints;
   shints.x=0;
   shints.y=0;
   shints.flags=0;
   bool pos=(XWMGeometry(d_display, DefaultScreen(d_display), position, NULL, 0, &shints, &shints.x, &shints.y,
      &shints.width, &shints.height, &shints.win_gravity) & (XValue | YValue));
   shints.min_width=winsize;
   shints.min_height=winsize;
   shints.max_width=winsize;
   shints.max_height=winsize;
   shints.base_width=winsize;
   shints.base_height=winsize;
   shints.flags=PMinSize | PMaxSize | PBaseSize;

   createWin(&w_main, shints.x, shints.y);

   if(wmaker || astep || pos)
      shints.flags |= USPosition;
   if(wmaker){
      wmhints.initial_state=WithdrawnState;
      wmhints.flags=WindowGroupHint | StateHint | IconWindowHint;
      createWin(&w_icon, shints.x, shints.y);
      w_activewin=w_icon;
      wmhints.icon_window=w_icon;
   }
   else{
      wmhints.initial_state=NormalState;
      wmhints.flags=WindowGroupHint | StateHint;
      w_activewin=w_main;
   }
   wmhints.window_group=w_main;
   XSetWMHints(d_display, w_main, &wmhints);
   XSetWMNormalHints(d_display, w_main, &shints);
   XSetCommand(d_display, w_main, argv, argc);
   XStoreName(d_display, w_main, NAME);
   XSetIconName(d_display, w_main, NAME);
   XSetWMProtocols(d_display, w_activewin, &deleteWin, 1);
}

void freeXWin(){
   XDestroyWindow(d_display, w_main);
   if(wmaker)
      XDestroyWindow(d_display, w_icon);
   XCloseDisplay(d_display);
}

void createWin(Window *win, int x, int y){
   XClassHint classHint;
   *win=XCreateSimpleWindow(d_display, w_root, x, y, winsize, winsize, 0, 0, 0);
   classHint.res_name=NAME;
   classHint.res_class=CLASS;
   XSetClassHint(d_display, *win, &classHint);
}

unsigned long getColor(char *colorname){
   XColor color;
   XWindowAttributes winattr;
   XGetWindowAttributes(d_display, w_root, &winattr);
   color.pixel=0;
   XParseColor(d_display, winattr.colormap, colorname, &color);
   color.flags=DoRed | DoGreen | DoBlue;
   XAllocColor(d_display, winattr.colormap, &color);
   return color.pixel;
}

unsigned long mixColor(char *colorname1, int prop1, char *colorname2, int prop2){
   XColor color, color1, color2;
   XWindowAttributes winattr;
   XGetWindowAttributes(d_display, w_root, &winattr);
   XParseColor(d_display, winattr.colormap, colorname1, &color1);
   XParseColor(d_display, winattr.colormap, colorname2, &color2);
   color.pixel=0;
   color.red=(color1.red*prop1+color2.red*prop2)/(prop1+prop2);
   color.green=(color1.green*prop1+color2.green*prop2)/(prop1+prop2);
   color.blue=(color1.blue*prop1+color2.blue*prop2)/(prop1+prop2);
   color.flags=DoRed | DoGreen | DoBlue;
   XAllocColor(d_display, winattr.colormap, &color);
   return color.pixel;
}

void scanArgs(int argc, char **argv){
}

void motionEvent(XMotionEvent *xev) {
   int x=xev->x-(winsize/2-32);
   int y=xev->y-(winsize/2-32);
}

void repaint(){
   XCopyArea(d_display, pm_disp, w_activewin, gc_gc, 0, 0, 64, 64, winsize/2-32, winsize/2-32);
   XEvent xev;
   while(XCheckTypedEvent(d_display, Expose, &xev));
}

void update(){
}


